Micron Document
🎖️GitЯра🎖️

Commit 3fe1deb01ccbc17b2d08941cd3dfed7b747dd325


Parents : 3930252
Author : James Rich <2199651+jamesarich@users.noreply.github.com>
Signature : Signature validation error
Date : 2026-06-19T13:23:12-05:00
Committer : GitHub <noreply@github.com>
Date : 2026-06-19T18:23:12Z

perf(node): add stable keys and contentType to telemetry chart lists (#5869)

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>

Changes
Diff

diff --git a/core/ui/src/commonMain/kotlin/org/meshtastic/core/ui/qr/ScannedQrCodeDialog.kt b/core/ui/src/commonMain/kotlin/org/meshtastic/core/ui/qr/ScannedQrCodeDialog.kt
index a96617957c..ed5f8c9f92 100644
--- a/core/ui/src/commonMain/kotlin/org/meshtastic/core/ui/qr/ScannedQrCodeDialog.kt
+++ b/core/ui/src/commonMain/kotlin/org/meshtastic/core/ui/qr/ScannedQrCodeDialog.kt
@@ -202,7 +202,10 @@ fun ScannedQrCodeDialog(
)
}
- itemsIndexed(channelSet.settings) { index, channel ->
+ itemsIndexed(channelSet.settings, key = { index, _ -> index }, contentType = { _, _ -> "channel" }) {
+ index,
+ channel,
+ ->
val isExisting = !shouldReplace && index < channels.settings.size
val channelObj = Channel(channel, channelSet.lora_config ?: Channel.default.loraConfig)
ChannelSelection(

diff --git a/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/AirQualityMetrics.kt b/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/AirQualityMetrics.kt
index 03504af65a..047026f900 100644
--- a/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/AirQualityMetrics.kt
+++ b/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/AirQualityMetrics.kt
@@ -166,7 +166,11 @@ fun AirQualityMetricsScreen(viewModel: MetricsViewModel, onNavigateUp: () -> Uni
},
listPart = { modifier, selectedX, lazyListState, onCardClick ->
LazyColumn(modifier = modifier.fillMaxSize(), state = lazyListState) {
- itemsIndexed(data) { _, telemetry ->
+ itemsIndexed(
+ data,
+ key = { _, telemetry -> telemetry.time },
+ contentType = { _, _ -> "air_quality_metrics" },
+ ) { _, telemetry ->
AirQualityMetricsCard(
telemetry = telemetry,
isSelected = telemetry.time.toDouble() == selectedX,

diff --git a/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/DeviceMetrics.kt b/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/DeviceMetrics.kt
index 8aa1569bdf..74db190326 100644
--- a/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/DeviceMetrics.kt
+++ b/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/DeviceMetrics.kt
@@ -191,7 +191,11 @@ fun DeviceMetricsScreen(viewModel: MetricsViewModel, onNavigateUp: () -> Unit) {
},
listPart = { modifier, selectedX, lazyListState, onCardClick ->
LazyColumn(modifier = modifier.fillMaxSize(), state = lazyListState) {
- itemsIndexed(data) { _, telemetry ->
+ itemsIndexed(
+ data,
+ key = { _, telemetry -> telemetry.time },
+ contentType = { _, _ -> "device_metrics" },
+ ) { _, telemetry ->
DeviceMetricsCard(
telemetry = telemetry,
isSelected = telemetry.time.toDouble() == selectedX,
@@ -560,7 +564,11 @@ private fun DeviceMetricsScreenPreview() {
/* Device Metric Cards */
LazyColumn(modifier = Modifier.fillMaxSize()) {
- itemsIndexed(telemetries) { _, telemetry ->
+ itemsIndexed(
+ telemetries,
+ key = { _, telemetry -> telemetry.time },
+ contentType = { _, _ -> "device_metrics" },
+ ) { _, telemetry ->
DeviceMetricsCard(telemetry = telemetry, isSelected = false, onClick = {})
}
}

diff --git a/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/EnvironmentMetrics.kt b/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/EnvironmentMetrics.kt
index bb2debd454..de6a01c978 100644
--- a/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/EnvironmentMetrics.kt
+++ b/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/EnvironmentMetrics.kt
@@ -115,7 +115,11 @@ fun EnvironmentMetricsScreen(viewModel: MetricsViewModel, onNavigateUp: () -> Un
},
listPart = { modifier, selectedX, lazyListState, onCardClick ->
LazyColumn(modifier = modifier.fillMaxSize(), state = lazyListState) {
- itemsIndexed(filteredTelemetries) { _, telemetry ->
+ itemsIndexed(
+ filteredTelemetries,
+ key = { _, telemetry -> telemetry.time },
+ contentType = { _, _ -> "environment_metrics" },
+ ) { _, telemetry ->
EnvironmentMetricsCard(
telemetry = telemetry,
environmentDisplayFahrenheit = state.isFahrenheit,

diff --git a/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/PaxMetrics.kt b/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/PaxMetrics.kt
index 7a44405ab1..d88c19e03a 100644
--- a/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/PaxMetrics.kt
+++ b/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/PaxMetrics.kt
@@ -231,7 +231,11 @@ fun PaxMetricsScreen(metricsViewModel: MetricsViewModel, onNavigateUp: () -> Uni
state = lazyListState,
contentPadding = PaddingValues(horizontal = 16.dp),
) {
- itemsIndexed(paxMetrics) { _, (log, pax) ->
+ itemsIndexed(
+ paxMetrics,
+ key = { _, (log, _) -> log.uuid },
+ contentType = { _, _ -> "pax_metrics" },
+ ) { _, (log, pax) ->
PaxMetricsItem(
log = log,
pax = pax,

diff --git a/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/PositionLogScreens.kt b/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/PositionLogScreens.kt
index a52f046c5b..86a1c25892 100644
--- a/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/PositionLogScreens.kt
+++ b/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/PositionLogScreens.kt
@@ -70,7 +70,11 @@ fun PositionLogScreen(viewModel: MetricsViewModel, onNavigateUp: () -> Unit) {
},
listPart = { modifier, selectedX, lazyListState, onCardClick ->
LazyColumn(modifier = modifier.fillMaxSize(), state = lazyListState) {
- itemsIndexed(positions) { _, position ->
+ itemsIndexed(
+ positions,
+ key = { _, position -> position.time },
+ contentType = { _, _ -> "position_log" },
+ ) { _, position ->
PositionCard(
position = position,
displayUnits = state.displayUnits,

diff --git a/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/PowerMetrics.kt b/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/PowerMetrics.kt
index 006acf37e7..10df7d752a 100644
--- a/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/PowerMetrics.kt
+++ b/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/PowerMetrics.kt
@@ -159,7 +159,11 @@ fun PowerMetricsScreen(viewModel: MetricsViewModel, onNavigateUp: () -> Unit) {
},
listPart = { modifier, selectedX, lazyListState, onCardClick ->
LazyColumn(modifier = modifier.fillMaxSize(), state = lazyListState) {
- itemsIndexed(data) { _, telemetry ->
+ itemsIndexed(
+ data,
+ key = { _, telemetry -> telemetry.time },
+ contentType = { _, _ -> "power_metrics" },
+ ) { _, telemetry ->
PowerMetricsCard(
telemetry = telemetry,
isSelected = telemetry.time.toDouble() == selectedX,

diff --git a/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/SignalMetrics.kt b/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/SignalMetrics.kt
index 7e0bf083b9..77a152cacb 100644
--- a/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/SignalMetrics.kt
+++ b/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/metrics/SignalMetrics.kt
@@ -114,12 +114,22 @@ private val LEGEND_DATA =
private sealed interface SignalLogEntry {
val timeSeconds: Int
+ /** Stable, collision-free identity for use as a LazyColumn item key across both entry types. */
+ val key: Any
+
+ /** Distinguishes the two card layouts so Compose can reuse compositions per type. */
+ val contentType: Any
+
data class LocalStatsEntry(val telemetry: Telemetry) : SignalLogEntry {
override val timeSeconds: Int = telemetry.time
+ override val key: Any = "local_stats_${telemetry.time}"
+ override val contentType: Any = "local_stats"
}
data class PacketEntry(val meshPacket: MeshPacket) : SignalLogEntry {
override val timeSeconds: Int = meshPacket.rx_time
+ override val key: Any = "packet_${meshPacket.id}"
+ override val contentType: Any = "signal_packet"
}
}
@@ -204,7 +214,11 @@ fun SignalMetricsScreen(viewModel: MetricsViewModel, onNavigateUp: () -> Unit, m
}
} else {
LazyColumn(modifier = contentModifier.fillMaxSize(), state = lazyListState) {
- itemsIndexed(data) { _, entry ->
+ itemsIndexed(
+ data,
+ key = { _, entry -> entry.key },
+ contentType = { _, entry -> entry.contentType },
+ ) { _, entry ->
when (entry) {
is SignalLogEntry.LocalStatsEntry ->
LocalStatsCard(

Served by rngit 1.4.2 - Generated in 0.14s